Added standard diviation
authorJeroen van der Heijden <jeroen@transceptor.technology>
Wed, 28 Mar 2018 14:45:57 +0000 (16:45 +0200)
committerJeroen van der Heijden <jeroen@transceptor.technology>
Wed, 28 Mar 2018 14:45:57 +0000 (16:45 +0200)
grammar/gogrammar/grammar.go
grammar/grammar.py
include/siri/grammar/grammar.h
src/siri/db/aggregate.c
src/siri/grammar/grammar.c
src/test/test.c

index 8f2df908732f4571792882774ab943ab20b1e3b1..562086ac47db975dca7be133b15a6e856154d87c 100644 (file)
@@ -4,7 +4,7 @@ package grammar
 // should be used with the goleri module.
 //
 // Source class: SiriGrammar
-// Created at: 2017-08-14 15:06:00
+// Created at: 2018-03-28 09:32:13
 
 import (
        "regexp"
@@ -64,6 +64,7 @@ const (
        GidFMin = iota
        GidFPoints = iota
        GidFPvariance = iota
+       GidFStddev = iota
        GidFSum = iota
        GidFVariance = iota
        GidGrantStmt = iota
@@ -205,6 +206,7 @@ const (
        GidKStart = iota
        GidKStartupTime = iota
        GidKStatus = iota
+       GidKStddev = iota
        GidKString = iota
        GidKSuffix = iota
        GidKSum = iota
@@ -406,6 +408,7 @@ func SiriGrammar() *goleri.Grammar {
        kStart := goleri.NewKeyword(GidKStart, "start", false)
        kStartupTime := goleri.NewKeyword(GidKStartupTime, "startup_time", false)
        kStatus := goleri.NewKeyword(GidKStatus, "status", false)
+       kStddev := goleri.NewKeyword(GidKStddev, "stddev", false)
        kString := goleri.NewKeyword(GidKString, "string", false)
        kSuffix := goleri.NewKeyword(GidKSuffix, "suffix", false)
        kSum := goleri.NewKeyword(GidKSum, "sum", false)
@@ -1065,6 +1068,13 @@ func SiriGrammar() *goleri.Grammar {
                timeExpr,
                goleri.NewToken(NoGid, ")"),
        )
+       fStddev := goleri.NewSequence(
+               GidFStddev,
+               kStddev,
+               goleri.NewToken(NoGid, "("),
+               timeExpr,
+               goleri.NewToken(NoGid, ")"),
+       )
        fFilter := goleri.NewSequence(
                GidFFilter,
                kFilter,
@@ -1098,6 +1108,7 @@ func SiriGrammar() *goleri.Grammar {
                        kCount,
                        kVariance,
                        kPvariance,
+                       kStddev,
                ),
                goleri.NewToken(NoGid, ")"),
        )
@@ -1116,6 +1127,7 @@ func SiriGrammar() *goleri.Grammar {
                fCount,
                fVariance,
                fPvariance,
+               fStddev,
                fDifference,
                fDerivative,
                fFilter,
@@ -1555,100 +1567,100 @@ func SiriGrammar() *goleri.Grammar {
                ), goleri.NewToken(NoGid, ","), 0, 0, false),
        )
        timeitStmt := goleri.NewRepeat(GidTimeitStmt, kTimeit, 1, 1)
-       helpShow := goleri.NewKeyword(GidHelpShow, "show", false)
-       helpRevoke := goleri.NewKeyword(GidHelpRevoke, "revoke", false)
-       helpNoaccess := goleri.NewKeyword(GidHelpNoaccess, "noaccess", false)
-       helpFunctions := goleri.NewKeyword(GidHelpFunctions, "functions", false)
+       helpDropSeries := goleri.NewKeyword(GidHelpDropSeries, "series", false)
+       helpDropGroup := goleri.NewKeyword(GidHelpDropGroup, "group", false)
+       helpDropShards := goleri.NewKeyword(GidHelpDropShards, "shards", false)
+       helpDropServer := goleri.NewKeyword(GidHelpDropServer, "server", false)
+       helpDropUser := goleri.NewKeyword(GidHelpDropUser, "user", false)
+       helpDrop := goleri.NewSequence(
+               GidHelpDrop,
+               kDrop,
+               goleri.NewOptional(NoGid, goleri.NewChoice(
+                       NoGid,
+                       true,
+                       helpDropSeries,
+                       helpDropGroup,
+                       helpDropShards,
+                       helpDropServer,
+                       helpDropUser,
+               )),
+       )
        helpGrant := goleri.NewKeyword(GidHelpGrant, "grant", false)
-       helpAccess := goleri.NewKeyword(GidHelpAccess, "access", false)
-       helpListUsers := goleri.NewKeyword(GidHelpListUsers, "users", false)
-       helpListPools := goleri.NewKeyword(GidHelpListPools, "pools", false)
-       helpListSeries := goleri.NewKeyword(GidHelpListSeries, "series", false)
-       helpListServers := goleri.NewKeyword(GidHelpListServers, "servers", false)
+       helpSelect := goleri.NewKeyword(GidHelpSelect, "select", false)
        helpListGroups := goleri.NewKeyword(GidHelpListGroups, "groups", false)
+       helpListSeries := goleri.NewKeyword(GidHelpListSeries, "series", false)
+       helpListPools := goleri.NewKeyword(GidHelpListPools, "pools", false)
+       helpListUsers := goleri.NewKeyword(GidHelpListUsers, "users", false)
        helpListShards := goleri.NewKeyword(GidHelpListShards, "shards", false)
+       helpListServers := goleri.NewKeyword(GidHelpListServers, "servers", false)
        helpList := goleri.NewSequence(
                GidHelpList,
                kList,
                goleri.NewOptional(NoGid, goleri.NewChoice(
                        NoGid,
                        true,
-                       helpListUsers,
-                       helpListPools,
-                       helpListSeries,
-                       helpListServers,
                        helpListGroups,
+                       helpListSeries,
+                       helpListPools,
+                       helpListUsers,
                        helpListShards,
+                       helpListServers,
                )),
        )
+       helpRevoke := goleri.NewKeyword(GidHelpRevoke, "revoke", false)
+       helpShow := goleri.NewKeyword(GidHelpShow, "show", false)
+       helpTimezones := goleri.NewKeyword(GidHelpTimezones, "timezones", false)
+       helpNoaccess := goleri.NewKeyword(GidHelpNoaccess, "noaccess", false)
+       helpAccess := goleri.NewKeyword(GidHelpAccess, "access", false)
+       helpFunctions := goleri.NewKeyword(GidHelpFunctions, "functions", false)
+       helpCreateUser := goleri.NewKeyword(GidHelpCreateUser, "user", false)
+       helpCreateGroup := goleri.NewKeyword(GidHelpCreateGroup, "group", false)
+       helpCreate := goleri.NewSequence(
+               GidHelpCreate,
+               kCreate,
+               goleri.NewOptional(NoGid, goleri.NewChoice(
+                       NoGid,
+                       true,
+                       helpCreateUser,
+                       helpCreateGroup,
+               )),
+       )
+       helpAlterUser := goleri.NewKeyword(GidHelpAlterUser, "user", false)
+       helpAlterServer := goleri.NewKeyword(GidHelpAlterServer, "server", false)
+       helpAlterServers := goleri.NewKeyword(GidHelpAlterServers, "servers", false)
        helpAlterDatabase := goleri.NewKeyword(GidHelpAlterDatabase, "database", false)
        helpAlterGroup := goleri.NewKeyword(GidHelpAlterGroup, "group", false)
-       helpAlterServers := goleri.NewKeyword(GidHelpAlterServers, "servers", false)
-       helpAlterServer := goleri.NewKeyword(GidHelpAlterServer, "server", false)
-       helpAlterUser := goleri.NewKeyword(GidHelpAlterUser, "user", false)
        helpAlter := goleri.NewSequence(
                GidHelpAlter,
                kAlter,
                goleri.NewOptional(NoGid, goleri.NewChoice(
                        NoGid,
                        true,
+                       helpAlterUser,
+                       helpAlterServer,
+                       helpAlterServers,
                        helpAlterDatabase,
                        helpAlterGroup,
-                       helpAlterServers,
-                       helpAlterServer,
-                       helpAlterUser,
                )),
        )
-       helpCountSeries := goleri.NewKeyword(GidHelpCountSeries, "series", false)
        helpCountServers := goleri.NewKeyword(GidHelpCountServers, "servers", false)
-       helpCountGroups := goleri.NewKeyword(GidHelpCountGroups, "groups", false)
        helpCountShards := goleri.NewKeyword(GidHelpCountShards, "shards", false)
-       helpCountUsers := goleri.NewKeyword(GidHelpCountUsers, "users", false)
+       helpCountGroups := goleri.NewKeyword(GidHelpCountGroups, "groups", false)
        helpCountPools := goleri.NewKeyword(GidHelpCountPools, "pools", false)
+       helpCountSeries := goleri.NewKeyword(GidHelpCountSeries, "series", false)
+       helpCountUsers := goleri.NewKeyword(GidHelpCountUsers, "users", false)
        helpCount := goleri.NewSequence(
                GidHelpCount,
                kCount,
                goleri.NewOptional(NoGid, goleri.NewChoice(
                        NoGid,
                        true,
-                       helpCountSeries,
                        helpCountServers,
-                       helpCountGroups,
                        helpCountShards,
-                       helpCountUsers,
+                       helpCountGroups,
                        helpCountPools,
-               )),
-       )
-       helpSelect := goleri.NewKeyword(GidHelpSelect, "select", false)
-       helpCreateGroup := goleri.NewKeyword(GidHelpCreateGroup, "group", false)
-       helpCreateUser := goleri.NewKeyword(GidHelpCreateUser, "user", false)
-       helpCreate := goleri.NewSequence(
-               GidHelpCreate,
-               kCreate,
-               goleri.NewOptional(NoGid, goleri.NewChoice(
-                       NoGid,
-                       true,
-                       helpCreateGroup,
-                       helpCreateUser,
-               )),
-       )
-       helpTimezones := goleri.NewKeyword(GidHelpTimezones, "timezones", false)
-       helpDropGroup := goleri.NewKeyword(GidHelpDropGroup, "group", false)
-       helpDropUser := goleri.NewKeyword(GidHelpDropUser, "user", false)
-       helpDropServer := goleri.NewKeyword(GidHelpDropServer, "server", false)
-       helpDropSeries := goleri.NewKeyword(GidHelpDropSeries, "series", false)
-       helpDropShards := goleri.NewKeyword(GidHelpDropShards, "shards", false)
-       helpDrop := goleri.NewSequence(
-               GidHelpDrop,
-               kDrop,
-               goleri.NewOptional(NoGid, goleri.NewChoice(
-                       NoGid,
-                       true,
-                       helpDropGroup,
-                       helpDropUser,
-                       helpDropServer,
-                       helpDropSeries,
-                       helpDropShards,
+                       helpCountSeries,
+                       helpCountUsers,
                )),
        )
        helpTimeit := goleri.NewKeyword(GidHelpTimeit, "timeit", false)
@@ -1658,19 +1670,19 @@ func SiriGrammar() *goleri.Grammar {
                goleri.NewOptional(NoGid, goleri.NewChoice(
                        NoGid,
                        true,
-                       helpShow,
+                       helpDrop,
+                       helpGrant,
+                       helpSelect,
+                       helpList,
                        helpRevoke,
+                       helpShow,
+                       helpTimezones,
                        helpNoaccess,
-                       helpFunctions,
-                       helpGrant,
                        helpAccess,
-                       helpList,
+                       helpFunctions,
+                       helpCreate,
                        helpAlter,
                        helpCount,
-                       helpSelect,
-                       helpCreate,
-                       helpTimezones,
-                       helpDrop,
                        helpTimeit,
                )),
        )
index f50a2836e4ca638a292f4992667a907a2841ffdc..8e033ea70ed398c44a69631acfc28968c17288fd 100644 (file)
@@ -140,6 +140,7 @@ class SiriGrammar(Grammar):
     k_start = Keyword('start')
     k_startup_time = Keyword('startup_time')
     k_status = Keyword('status')
+    k_stddev = Keyword('stddev')
     k_string = Keyword('string')
     k_suffix = Keyword('suffix')
     k_sum = Keyword('sum')
@@ -457,6 +458,10 @@ class SiriGrammar(Grammar):
     f_pvariance = Sequence(
         k_pvariance,
         '(', time_expr, ')')
+    f_stddev = Sequence(
+        k_stddev,
+        '(', time_expr, ')')
+
     f_filter = Sequence(
         k_filter,
         '(',
@@ -483,6 +488,7 @@ class SiriGrammar(Grammar):
             k_count,
             k_variance,
             k_pvariance,
+            k_stddev,
             most_greedy=False),
         ')')
 
@@ -499,6 +505,7 @@ class SiriGrammar(Grammar):
         f_count,
         f_variance,
         f_pvariance,
+        f_stddev,
         f_difference,
         f_derivative,
         f_filter,
index adac3a8c0b41a6722181bdc6d4a7cd0371730236..9f77604f0ee4a98dce882e33604a3d3f65c525af 100644 (file)
@@ -5,7 +5,7 @@
  * should be used with the libcleri module.
  *
  * Source class: SiriGrammar
- * Created at: 2017-08-14 15:06:00
+ * Created at: 2018-03-28 09:32:13
  */
 #ifndef CLERI_EXPORT_SIRI_GRAMMAR_GRAMMAR_H_
 #define CLERI_EXPORT_SIRI_GRAMMAR_GRAMMAR_H_
@@ -64,6 +64,7 @@ enum cleri_grammar_ids {
     CLERI_GID_F_MIN,
     CLERI_GID_F_POINTS,
     CLERI_GID_F_PVARIANCE,
+    CLERI_GID_F_STDDEV,
     CLERI_GID_F_SUM,
     CLERI_GID_F_VARIANCE,
     CLERI_GID_GRANT_STMT,
@@ -205,6 +206,7 @@ enum cleri_grammar_ids {
     CLERI_GID_K_START,
     CLERI_GID_K_STARTUP_TIME,
     CLERI_GID_K_STATUS,
+    CLERI_GID_K_STDDEV,
     CLERI_GID_K_STRING,
     CLERI_GID_K_SUFFIX,
     CLERI_GID_K_SUM,
index 646d0f2aea18c9d9c92a9c765044d1c6032e14da..4fcca4036782e7130d1d4efa54f51d34e4544bc1 100644 (file)
@@ -19,6 +19,7 @@
 #include <slist/slist.h>
 #include <stddef.h>
 #include <strextra/strextra.h>
+#include <math.h>
 
 #define AGGR_NEW                                    \
 if ((aggr = AGGREGATE_new(gid)) == NULL)            \
@@ -147,6 +148,11 @@ static int aggr_variance(
         siridb_aggr_t * aggr,
         char * err_msg);
 
+static int aggr_stddev(
+        siridb_point_t * point,
+        siridb_points_t * points,
+        siridb_aggr_t * aggr,
+        char * err_msg);
 /*
  * Initialize aggregates.
  */
@@ -170,6 +176,7 @@ void siridb_init_aggregates(void)
     AGGREGATES[CLERI_GID_F_PVARIANCE - F_OFFSET] = aggr_pvariance;
     AGGREGATES[CLERI_GID_F_SUM - F_OFFSET] = aggr_sum;
     AGGREGATES[CLERI_GID_F_VARIANCE - F_OFFSET] = aggr_variance;
+    AGGREGATES[CLERI_GID_F_STDDEV - F_OFFSET] = aggr_stddev;
 }
 
 /*
@@ -256,6 +263,10 @@ slist_t * siridb_aggregate_list(cleri_children_t * children, char * err_msg)
                     aggr->gid = CLERI_GID_F_PVARIANCE;
                     break;
 
+                case CLERI_GID_K_STDDEV:
+                    aggr->gid = CLERI_GID_F_STDDEV;
+                    break;
+
                 default:
                     assert (0);
                     break;
@@ -382,6 +393,7 @@ slist_t * siridb_aggregate_list(cleri_children_t * children, char * err_msg)
         case CLERI_GID_F_PVARIANCE:
         case CLERI_GID_F_SUM:
         case CLERI_GID_F_VARIANCE:
+        case CLERI_GID_F_STDDEV:
             AGGR_NEW
             aggr->group_by = children->node->children->node->children->
                     next->next->node->result;
@@ -866,6 +878,7 @@ static siridb_points_t * AGGREGATE_group_by(
     case CLERI_GID_F_MEDIAN:
     case CLERI_GID_F_PVARIANCE:
     case CLERI_GID_F_VARIANCE:
+    case CLERI_GID_F_STDDEV:
     case CLERI_GID_F_DERIVATIVE:
         points = siridb_points_new(max_sz, TP_DOUBLE);
         break;
@@ -1421,3 +1434,33 @@ static int aggr_variance(
 
     return 0;
 }
+
+static int aggr_stddev(
+        siridb_point_t * point,
+        siridb_points_t * points,
+        siridb_aggr_t * aggr __attribute__((unused)),
+        char * err_msg)
+{
+#if DEBUG
+    assert (points->len);
+#endif
+
+    switch (points->tp)
+    {
+    case TP_STRING:
+        sprintf(err_msg, "Cannot use stddev() on string type.");
+        return -1;
+
+    case TP_INT:
+    case TP_DOUBLE:
+        point->val.real = (points->len > 1) ?
+                sqrt(siridb_variance(points) / (points->len - 1)) : 0.0;
+        break;
+
+    default:
+        assert (0);
+        break;
+    }
+
+    return 0;
+}
index 523bb8ed3bf5e11dafcc9a8642ab19ac99bec6fe..8c61c8618aaa8bced6ec27f1121cd015d00bb65a 100644 (file)
@@ -5,7 +5,7 @@
  * should be used with the libcleri module.
  *
  * Source class: SiriGrammar
- * Created at: 2017-08-14 15:06:00
+ * Created at: 2018-03-28 09:32:13
  */
 
 #include "siri/grammar/grammar.h"
@@ -134,6 +134,7 @@ cleri_grammar_t * compile_grammar(void)
     cleri_t * k_start = cleri_keyword(CLERI_GID_K_START, "start", CLERI_CASE_SENSITIVE);
     cleri_t * k_startup_time = cleri_keyword(CLERI_GID_K_STARTUP_TIME, "startup_time", CLERI_CASE_SENSITIVE);
     cleri_t * k_status = cleri_keyword(CLERI_GID_K_STATUS, "status", CLERI_CASE_SENSITIVE);
+    cleri_t * k_stddev = cleri_keyword(CLERI_GID_K_STDDEV, "stddev", CLERI_CASE_SENSITIVE);
     cleri_t * k_string = cleri_keyword(CLERI_GID_K_STRING, "string", CLERI_CASE_SENSITIVE);
     cleri_t * k_suffix = cleri_keyword(CLERI_GID_K_SUFFIX, "suffix", CLERI_CASE_SENSITIVE);
     cleri_t * k_sum = cleri_keyword(CLERI_GID_K_SUM, "sum", CLERI_CASE_SENSITIVE);
@@ -891,6 +892,14 @@ cleri_grammar_t * compile_grammar(void)
         time_expr,
         cleri_token(CLERI_NONE, ")")
     );
+    cleri_t * f_stddev = cleri_sequence(
+        CLERI_GID_F_STDDEV,
+        4,
+        k_stddev,
+        cleri_token(CLERI_NONE, "("),
+        time_expr,
+        cleri_token(CLERI_NONE, ")")
+    );
     cleri_t * f_filter = cleri_sequence(
         CLERI_GID_F_FILTER,
         5,
@@ -917,7 +926,7 @@ cleri_grammar_t * compile_grammar(void)
         cleri_choice(
             CLERI_NONE,
             CLERI_FIRST_MATCH,
-            10,
+            11,
             k_mean,
             k_median,
             k_median_high,
@@ -927,14 +936,15 @@ cleri_grammar_t * compile_grammar(void)
             k_max,
             k_count,
             k_variance,
-            k_pvariance
+            k_pvariance,
+            k_stddev
         ),
         cleri_token(CLERI_NONE, ")")
     );
     cleri_t * aggregate_functions = cleri_list(CLERI_GID_AGGREGATE_FUNCTIONS, cleri_choice(
         CLERI_NONE,
         CLERI_FIRST_MATCH,
-        15,
+        16,
         f_points,
         f_limit,
         f_mean,
@@ -947,6 +957,7 @@ cleri_grammar_t * compile_grammar(void)
         f_count,
         f_variance,
         f_pvariance,
+        f_stddev,
         f_difference,
         f_derivative,
         f_filter
@@ -1453,18 +1464,34 @@ cleri_grammar_t * compile_grammar(void)
         ), cleri_token(CLERI_NONE, ","), 0, 0, 0)
     );
     cleri_t * timeit_stmt = cleri_dup(CLERI_GID_TIMEIT_STMT, k_timeit);
-    cleri_t * help_show = cleri_keyword(CLERI_GID_HELP_SHOW, "show", CLERI_CASE_SENSITIVE);
-    cleri_t * help_revoke = cleri_keyword(CLERI_GID_HELP_REVOKE, "revoke", CLERI_CASE_SENSITIVE);
-    cleri_t * help_noaccess = cleri_keyword(CLERI_GID_HELP_NOACCESS, "noaccess", CLERI_CASE_SENSITIVE);
-    cleri_t * help_functions = cleri_keyword(CLERI_GID_HELP_FUNCTIONS, "functions", CLERI_CASE_SENSITIVE);
+    cleri_t * help_drop_series = cleri_keyword(CLERI_GID_HELP_DROP_SERIES, "series", CLERI_CASE_SENSITIVE);
+    cleri_t * help_drop_group = cleri_keyword(CLERI_GID_HELP_DROP_GROUP, "group", CLERI_CASE_SENSITIVE);
+    cleri_t * help_drop_shards = cleri_keyword(CLERI_GID_HELP_DROP_SHARDS, "shards", CLERI_CASE_SENSITIVE);
+    cleri_t * help_drop_server = cleri_keyword(CLERI_GID_HELP_DROP_SERVER, "server", CLERI_CASE_SENSITIVE);
+    cleri_t * help_drop_user = cleri_keyword(CLERI_GID_HELP_DROP_USER, "user", CLERI_CASE_SENSITIVE);
+    cleri_t * help_drop = cleri_sequence(
+        CLERI_GID_HELP_DROP,
+        2,
+        k_drop,
+        cleri_optional(CLERI_NONE, cleri_choice(
+            CLERI_NONE,
+            CLERI_MOST_GREEDY,
+            5,
+            help_drop_series,
+            help_drop_group,
+            help_drop_shards,
+            help_drop_server,
+            help_drop_user
+        ))
+    );
     cleri_t * help_grant = cleri_keyword(CLERI_GID_HELP_GRANT, "grant", CLERI_CASE_SENSITIVE);
-    cleri_t * help_access = cleri_keyword(CLERI_GID_HELP_ACCESS, "access", CLERI_CASE_SENSITIVE);
-    cleri_t * help_list_users = cleri_keyword(CLERI_GID_HELP_LIST_USERS, "users", CLERI_CASE_SENSITIVE);
-    cleri_t * help_list_pools = cleri_keyword(CLERI_GID_HELP_LIST_POOLS, "pools", CLERI_CASE_SENSITIVE);
-    cleri_t * help_list_series = cleri_keyword(CLERI_GID_HELP_LIST_SERIES, "series", CLERI_CASE_SENSITIVE);
-    cleri_t * help_list_servers = cleri_keyword(CLERI_GID_HELP_LIST_SERVERS, "servers", CLERI_CASE_SENSITIVE);
+    cleri_t * help_select = cleri_keyword(CLERI_GID_HELP_SELECT, "select", CLERI_CASE_SENSITIVE);
     cleri_t * help_list_groups = cleri_keyword(CLERI_GID_HELP_LIST_GROUPS, "groups", CLERI_CASE_SENSITIVE);
+    cleri_t * help_list_series = cleri_keyword(CLERI_GID_HELP_LIST_SERIES, "series", CLERI_CASE_SENSITIVE);
+    cleri_t * help_list_pools = cleri_keyword(CLERI_GID_HELP_LIST_POOLS, "pools", CLERI_CASE_SENSITIVE);
+    cleri_t * help_list_users = cleri_keyword(CLERI_GID_HELP_LIST_USERS, "users", CLERI_CASE_SENSITIVE);
     cleri_t * help_list_shards = cleri_keyword(CLERI_GID_HELP_LIST_SHARDS, "shards", CLERI_CASE_SENSITIVE);
+    cleri_t * help_list_servers = cleri_keyword(CLERI_GID_HELP_LIST_SERVERS, "servers", CLERI_CASE_SENSITIVE);
     cleri_t * help_list = cleri_sequence(
         CLERI_GID_HELP_LIST,
         2,
@@ -1473,19 +1500,39 @@ cleri_grammar_t * compile_grammar(void)
             CLERI_NONE,
             CLERI_MOST_GREEDY,
             6,
-            help_list_users,
-            help_list_pools,
-            help_list_series,
-            help_list_servers,
             help_list_groups,
-            help_list_shards
+            help_list_series,
+            help_list_pools,
+            help_list_users,
+            help_list_shards,
+            help_list_servers
         ))
     );
+    cleri_t * help_revoke = cleri_keyword(CLERI_GID_HELP_REVOKE, "revoke", CLERI_CASE_SENSITIVE);
+    cleri_t * help_show = cleri_keyword(CLERI_GID_HELP_SHOW, "show", CLERI_CASE_SENSITIVE);
+    cleri_t * help_timezones = cleri_keyword(CLERI_GID_HELP_TIMEZONES, "timezones", CLERI_CASE_SENSITIVE);
+    cleri_t * help_noaccess = cleri_keyword(CLERI_GID_HELP_NOACCESS, "noaccess", CLERI_CASE_SENSITIVE);
+    cleri_t * help_access = cleri_keyword(CLERI_GID_HELP_ACCESS, "access", CLERI_CASE_SENSITIVE);
+    cleri_t * help_functions = cleri_keyword(CLERI_GID_HELP_FUNCTIONS, "functions", CLERI_CASE_SENSITIVE);
+    cleri_t * help_create_user = cleri_keyword(CLERI_GID_HELP_CREATE_USER, "user", CLERI_CASE_SENSITIVE);
+    cleri_t * help_create_group = cleri_keyword(CLERI_GID_HELP_CREATE_GROUP, "group", CLERI_CASE_SENSITIVE);
+    cleri_t * help_create = cleri_sequence(
+        CLERI_GID_HELP_CREATE,
+        2,
+        k_create,
+        cleri_optional(CLERI_NONE, cleri_choice(
+            CLERI_NONE,
+            CLERI_MOST_GREEDY,
+            2,
+            help_create_user,
+            help_create_group
+        ))
+    );
+    cleri_t * help_alter_user = cleri_keyword(CLERI_GID_HELP_ALTER_USER, "user", CLERI_CASE_SENSITIVE);
+    cleri_t * help_alter_server = cleri_keyword(CLERI_GID_HELP_ALTER_SERVER, "server", CLERI_CASE_SENSITIVE);
+    cleri_t * help_alter_servers = cleri_keyword(CLERI_GID_HELP_ALTER_SERVERS, "servers", CLERI_CASE_SENSITIVE);
     cleri_t * help_alter_database = cleri_keyword(CLERI_GID_HELP_ALTER_DATABASE, "database", CLERI_CASE_SENSITIVE);
     cleri_t * help_alter_group = cleri_keyword(CLERI_GID_HELP_ALTER_GROUP, "group", CLERI_CASE_SENSITIVE);
-    cleri_t * help_alter_servers = cleri_keyword(CLERI_GID_HELP_ALTER_SERVERS, "servers", CLERI_CASE_SENSITIVE);
-    cleri_t * help_alter_server = cleri_keyword(CLERI_GID_HELP_ALTER_SERVER, "server", CLERI_CASE_SENSITIVE);
-    cleri_t * help_alter_user = cleri_keyword(CLERI_GID_HELP_ALTER_USER, "user", CLERI_CASE_SENSITIVE);
     cleri_t * help_alter = cleri_sequence(
         CLERI_GID_HELP_ALTER,
         2,
@@ -1494,19 +1541,19 @@ cleri_grammar_t * compile_grammar(void)
             CLERI_NONE,
             CLERI_MOST_GREEDY,
             5,
-            help_alter_database,
-            help_alter_group,
-            help_alter_servers,
+            help_alter_user,
             help_alter_server,
-            help_alter_user
+            help_alter_servers,
+            help_alter_database,
+            help_alter_group
         ))
     );
-    cleri_t * help_count_series = cleri_keyword(CLERI_GID_HELP_COUNT_SERIES, "series", CLERI_CASE_SENSITIVE);
     cleri_t * help_count_servers = cleri_keyword(CLERI_GID_HELP_COUNT_SERVERS, "servers", CLERI_CASE_SENSITIVE);
-    cleri_t * help_count_groups = cleri_keyword(CLERI_GID_HELP_COUNT_GROUPS, "groups", CLERI_CASE_SENSITIVE);
     cleri_t * help_count_shards = cleri_keyword(CLERI_GID_HELP_COUNT_SHARDS, "shards", CLERI_CASE_SENSITIVE);
-    cleri_t * help_count_users = cleri_keyword(CLERI_GID_HELP_COUNT_USERS, "users", CLERI_CASE_SENSITIVE);
+    cleri_t * help_count_groups = cleri_keyword(CLERI_GID_HELP_COUNT_GROUPS, "groups", CLERI_CASE_SENSITIVE);
     cleri_t * help_count_pools = cleri_keyword(CLERI_GID_HELP_COUNT_POOLS, "pools", CLERI_CASE_SENSITIVE);
+    cleri_t * help_count_series = cleri_keyword(CLERI_GID_HELP_COUNT_SERIES, "series", CLERI_CASE_SENSITIVE);
+    cleri_t * help_count_users = cleri_keyword(CLERI_GID_HELP_COUNT_USERS, "users", CLERI_CASE_SENSITIVE);
     cleri_t * help_count = cleri_sequence(
         CLERI_GID_HELP_COUNT,
         2,
@@ -1515,48 +1562,12 @@ cleri_grammar_t * compile_grammar(void)
             CLERI_NONE,
             CLERI_MOST_GREEDY,
             6,
-            help_count_series,
             help_count_servers,
-            help_count_groups,
             help_count_shards,
-            help_count_users,
-            help_count_pools
-        ))
-    );
-    cleri_t * help_select = cleri_keyword(CLERI_GID_HELP_SELECT, "select", CLERI_CASE_SENSITIVE);
-    cleri_t * help_create_group = cleri_keyword(CLERI_GID_HELP_CREATE_GROUP, "group", CLERI_CASE_SENSITIVE);
-    cleri_t * help_create_user = cleri_keyword(CLERI_GID_HELP_CREATE_USER, "user", CLERI_CASE_SENSITIVE);
-    cleri_t * help_create = cleri_sequence(
-        CLERI_GID_HELP_CREATE,
-        2,
-        k_create,
-        cleri_optional(CLERI_NONE, cleri_choice(
-            CLERI_NONE,
-            CLERI_MOST_GREEDY,
-            2,
-            help_create_group,
-            help_create_user
-        ))
-    );
-    cleri_t * help_timezones = cleri_keyword(CLERI_GID_HELP_TIMEZONES, "timezones", CLERI_CASE_SENSITIVE);
-    cleri_t * help_drop_group = cleri_keyword(CLERI_GID_HELP_DROP_GROUP, "group", CLERI_CASE_SENSITIVE);
-    cleri_t * help_drop_user = cleri_keyword(CLERI_GID_HELP_DROP_USER, "user", CLERI_CASE_SENSITIVE);
-    cleri_t * help_drop_server = cleri_keyword(CLERI_GID_HELP_DROP_SERVER, "server", CLERI_CASE_SENSITIVE);
-    cleri_t * help_drop_series = cleri_keyword(CLERI_GID_HELP_DROP_SERIES, "series", CLERI_CASE_SENSITIVE);
-    cleri_t * help_drop_shards = cleri_keyword(CLERI_GID_HELP_DROP_SHARDS, "shards", CLERI_CASE_SENSITIVE);
-    cleri_t * help_drop = cleri_sequence(
-        CLERI_GID_HELP_DROP,
-        2,
-        k_drop,
-        cleri_optional(CLERI_NONE, cleri_choice(
-            CLERI_NONE,
-            CLERI_MOST_GREEDY,
-            5,
-            help_drop_group,
-            help_drop_user,
-            help_drop_server,
-            help_drop_series,
-            help_drop_shards
+            help_count_groups,
+            help_count_pools,
+            help_count_series,
+            help_count_users
         ))
     );
     cleri_t * help_timeit = cleri_keyword(CLERI_GID_HELP_TIMEIT, "timeit", CLERI_CASE_SENSITIVE);
@@ -1568,19 +1579,19 @@ cleri_grammar_t * compile_grammar(void)
             CLERI_NONE,
             CLERI_MOST_GREEDY,
             14,
-            help_show,
+            help_drop,
+            help_grant,
+            help_select,
+            help_list,
             help_revoke,
+            help_show,
+            help_timezones,
             help_noaccess,
-            help_functions,
-            help_grant,
             help_access,
-            help_list,
+            help_functions,
+            help_create,
             help_alter,
             help_count,
-            help_select,
-            help_create,
-            help_timezones,
-            help_drop,
             help_timeit
         ))
     );
index 88ee9af8efbfba5c0c1ef31d7d5d2828dc5dc3ae..52afabf3809e55d54a52b2290907724d64727299 100644 (file)
@@ -34,6 +34,7 @@
 #include <siri/version.h>
 #include <siri/db/lookup.h>
 #include <strextra/strextra.h>
+#include <math.h>
 
 #define TEST_OK 1
 #define TEST_FAILED -1
@@ -795,6 +796,35 @@ static int test_aggr_variance(void)
     return test_end(TEST_OK);
 }
 
+static int test_aggr_stddev(void)
+{
+    test_start("Testing standard deviation");
+
+    siridb_aggr_t aggr;
+    siridb_points_t * result;
+    char err_msg[SIRIDB_MAX_SIZE_ERR_MSG];
+    siridb_points_t * points = prepare_points();
+
+    aggr.gid = CLERI_GID_F_STDDEV;
+    aggr.group_by = 6;
+    aggr.limit = 0;
+    aggr.offset = 0;
+
+    result = siridb_aggregate_run(points, &aggr, err_msg);
+
+    assert (result != NULL);
+    assert (result->len == 4);
+    assert (result->tp == TP_DOUBLE);
+    assert (result->data->ts == 6 && result->data->val.real == sqrt(2.0));
+    assert ((result->data + 1)->ts == 12 &&
+            (result->data + 1)->val.real == 2.0);
+
+    siridb_points_free(result);
+    siridb_points_free(points);
+
+    return test_end(TEST_OK);
+}
+
 static int test_iso8601(void)
 {
     test_start("Testing iso8601");
@@ -952,6 +982,7 @@ int run_tests(void)
     rc += test_aggr_pvariance();
     rc += test_aggr_sum();
     rc += test_aggr_variance();
+    rc += test_aggr_stddev();
     rc += test_iso8601();
     rc += test_expr();
     rc += test_access();